home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / LIBRARY / DSUTIL12 / OS-BOOT / OS-BOOT.PAS < prev   
Pascal/Delphi Source File  |  1993-10-18  |  25KB  |  679 lines

  1. {-----------------------------------------------------------------------}
  2. { PROJECT        NON-PROFIT HIGH QUALITY PROFESSIONAL SOFTWARE,  }
  3. {            AVAILABLE FOR ALL WORLD                }
  4. { LIBRARY        SYSTEM UTILITIES                                }
  5. { MODULE        MULTIPLE-OPERATING-SYSTEMS-LOADER               }
  6. { FILE NAME        OS-BOOT.PAS                    }
  7. { PURPOSE        OS-loader from the fixed disk                   }
  8. { VERSION        1.30                        }
  9. { DATE            18-Oct-93                    }
  10. { DESIGN        Dmitry Stefankov                }
  11. { IMPLEMENTATION    Dmitry Stefankov                 }
  12. { COMPANY        Freelance Software Engineer            }
  13. { ADDRESS        Isakowskogo str, 4-2-30                }
  14. {            Moscow, 123181                    }
  15. {            USSR                        }
  16. {            Tel. 007 (095) 944-6304                }
  17. { COPYRIGHT NOTICE    Copyright (C) 1987-1993, Dmitry Stefankov    }
  18. { RESTRICTED RIGHTS    AVAILABLE ONLY FOR FREE DISTRIBUTION,           }
  19. {            NOT FOR COMMERCIAL PURPOSE            }
  20. { COMPUTER        IBM PC or compatible                }
  21. { OPERATING SYSTEM    MS/PC-DOS Version 3.30 or higher        }
  22. { COMPILER        Turbo Pascal Version 6.0            }
  23. {                       (Borland International Inc.)  or compatible     }
  24. { ASSEMBLY LANGUAGE    Microsoft MASM 5.10 or compatible               }
  25. { LINKER        Turbo Pascal internal                           }
  26. { ARGUMENTS        None                                            }
  27. { RETURN        See error return codes definitions        }
  28. { REQUIRES        Source Code Files                               }
  29. {                       NONE                                            }
  30. {                       External Object Files                           }
  31. {                       NONE                                            }
  32. {            Maintence Project Files                }
  33. {            NONE                        }
  34. { NATURAL LANGUAGE      English Language                                 }
  35. { SPECIAL        None                        }
  36. { DESCRIPTION        1. Read Master Boot Record.                     }
  37. {            1a. If our loader present then copy some info    }
  38. {                by user confirming                } 
  39. {            2. Extract the Partition Table from it and    }
  40. {               link with new loader code.             }
  41. {            3. Install a new Master Boot Record if user     }
  42. {                wants it                    }
  43. { REVISION HISTORY    Dima Stefankov (DS)                }
  44. {               1.00   13-Sep-92  DS  initial release        }
  45. {            1.01   14-Sep-92  DS  add saving old MBR to file}
  46. {                       1.02   21-Sep-92  DS  some corrections          }
  47. {                       1.10   08-Oct-92  DS  some style corrections    }
  48. {                       1.11   27-Oct-92  DS  some corrections          }
  49. {                       1.12   04-Nov-92  DS  some updates              }
  50. {            1.20   23-Mar-93  DS  some corrections        }
  51. {                       1.21   14-May-93  DS  some style updates        }
  52. {            1.30   18-Oct-93  DS  added a checking of copy  }
  53. {                                             already installed on disk }
  54. {-----------------------------------------------------------------------}
  55.  
  56.  
  57. {*======================= PROGRAM HEADER PART ==========================*}
  58.  
  59. PROGRAM   OS_LOADER_FROM_FIXED_DISK;
  60.  
  61.  
  62. {*** other modules ***}
  63. {*USES;*}
  64.  
  65.  
  66. {** switches for compilation **}
  67. {$S-}        {*  stack checking   *}
  68. {$R-}           {*  range checking   *}
  69.  
  70. {* generate version for loader code debugging *}
  71. {***$DEFINE  DebugVersion}
  72.  
  73.  
  74. {*========================== CONSTANTS PART ============================*}
  75.  
  76. CONST
  77.  
  78.     { program definitions }
  79.      asPurpose                  =       'OS-MultBoot';
  80.      asVersion                  =       '1.30';
  81.      asAuthor                   =       'Dima Stefankov';
  82.      asCopyright                =       'Copyright (c) 1987, 1993';
  83.      asProgram                  =       'OS-Boot';
  84.      asProgramPrompt            =       asProgram+': ';
  85.  
  86.      { exit codes }
  87.        errTerminateOK           =     0;
  88.        errBootStrapDebug        =     1;
  89.        errBadReadFixedDisk      =     2;
  90.        errBadWriteFixedDisk     =     3;
  91.        errUserInstallAbort      =     4;
  92.        errUserWriteAbort        =     5;
  93.        errMismatchLoaderCode    =     6;
  94.  
  95.     { miscellaneous }
  96.       aMaxTpStrLen              =     255;
  97.       asBlank                   =     '';
  98.       achHexPrefix              =     '$';
  99.       asFreeSlot                =     ' <*** free slot ***>';
  100.       asNonFreeSlot             =     ' <*** disk slot ***>';
  101.       aSectorSize               =     512;
  102.       aSecSizeInWords           =     aSectorSize DIV 2;
  103.       aQuit                     =     'Q';
  104.       achYes                    =     'Y';
  105.       achNo                     =     'N';
  106.       aDefExt                   =     'BIN';
  107.       aDosExtMark               =     '.';
  108.  
  109.     { ASCII codes }
  110.       achNULL                   =     00;
  111.       achLF                     =     10;
  112.       achCR                     =     13;
  113.       achOne                    =     '1';
  114.       achFour                   =     '4';
  115.  
  116.       {***** ATTENTION!!! Hard-coded values below. *****}
  117.       {***** Please modify carefully!              *****}
  118. {$IFDEF  DebugVersion}
  119.       adwBootSeg                =     $8000;     { segment at 512K }
  120. {$ELSE}
  121.       adwBootSeg                =     $0000;     { segment at 0K }
  122. {$ENDIF}
  123.      adwBootOfs                 =     $7C00;
  124.      adwRelBootOfs              =     adwBootOfs + aSectorSize;
  125.      adwPartitionTable        =     $1BE;
  126.      aPartitonEntrySize         =     $10;
  127.      aMaxAvailLogicalPartition    =     4;
  128.      adwBootMarkOfs             =     adwPartitionTable + (aPartitonEntrySize*aMaxAvailLogicalPartition);
  129.      adwBootSecID               =     $AA55;
  130.  
  131.      aOS_Desc_Str_Len           =     $16;      { these values found }
  132.      aOS_Desc_Ofs               =     $04;    { after assembly of  }
  133.      aOS_Desc_Start             =     $40-1;    { IPL procedure.     }      
  134.      aOS_Desc_Str_Len_Ext       =     aOS_Desc_Str_Len + 2;
  135.  
  136.      aDebugOff                  =     0;
  137.      aDebugOn                   =     1;
  138.  
  139.      aFarJumpOpCode             =     $EA;      { iAPX86 opcode }
  140.  
  141.      aRomKbdDriver              =     $16;      { IBM PC BIOS functions }
  142.      aRomDiskDriver             =     $13;
  143.      aRomVideoDriver            =     $10;
  144.  
  145.   { use for to check of installed version }
  146.      asCopyrightNotice          =     'OS-MultBoot (C) 1992 D.Stefankov';
  147.  
  148.  
  149. {*====================== TYPED CONSTANTS PART ==========================*}
  150.  
  151. TYPE
  152.  
  153.   {* strings *}
  154.        STR2                     =     STRING[2];
  155.        STR4                     =     STRING[4];
  156.        STR8                     =     STRING[8];
  157.  
  158.     {* Information about logical disk *}
  159.     recLogicalPartition  =  RECORD
  160.                  dbBootDriveMark              :       System.Byte;      {00}
  161.                  dbStartingHead               :       System.Byte;      {01}
  162.                  dwStartingCylSec             :       System.Word;      {02}
  163.                  dbOperatingSystemID          :       System.Byte;      {04}
  164.                  dbEndingHead                 :       System.Byte;      {05}
  165.                  dwEndingCylSec               :       System.Word;      {06}
  166.                  ddPrecedingSecs              :       System.Longint;   {08}
  167.                  ddSecsPerPartition           :       System.Longint;   {0C}
  168.                            END;
  169.     {* recLogicalPartition *}
  170.  
  171.     {* Master Boot Sector *}
  172.     recMasterBoot  =  RECORD
  173.          dbReservedCode           :  ARRAY[0..adwPartitionTable-1] OF System.Byte;              {000}
  174.          recDiskPartitionsTable   :  ARRAY[0..aMaxAvailLogicalPartition-1] OF recLogicalPartition;  {1BE}
  175.          dwValidBootRecID         :  System.Word;                                           {1FE}
  176.                            END;
  177.     {* recMasterBoot *}
  178.  
  179.  
  180. {*=========================== VARIABLES PART ===========================*}
  181.  
  182. VAR
  183.  
  184.    grecFixedDiskBoot    :   recMasterBoot;
  185.    gfOutStream          :   FILE  OF  recMasterBoot;
  186.    gsTempInput          :   STRING;
  187.    gdwOurBootRecLen    :   System.Word;
  188.    gdwMemOfs            :   System.Word;
  189.    gbStatusOk           :   System.Boolean;
  190.    gdbIndex             :   System.Byte;
  191.    gchIn                :   System.Char;
  192.  
  193.  
  194.  
  195. {*=========================== PROCEDURAL PART ==========================*}
  196.  
  197. PROCEDURE _IPL_Code; far; assembler;
  198. {* Initial program loader. *}
  199. {* Note 1: This procedure must be always first. *}
  200. {* Note 2: The length of code must be <= $1BE for non-debugging version. *}
  201. asm
  202. {$IFDEF  DebugVersion}
  203.         cmp      ax, aDebugOff        { Test for relocated code marker }
  204.         je       @InitCode
  205.  
  206.         mov      bx, cs               { Our Procedure in TP code segment }
  207.         mov      ds, bx               { We move it to new segment for debugging }
  208.         mov      ax, adwBootSeg
  209.         mov      es, ax
  210.         mov      cx, aSecSizeInWords
  211.         mov      si, 0
  212.         mov      di, adwBootOfs
  213.         push     es                   { Jump Segment into Stack }
  214.         push     di                   { Jump Offset  into Stack }
  215.         cld
  216.         rep      movsw
  217.  
  218.         mov      ax, aDebugOff        { we had relocated code }
  219.         retf                          { jump to relocated code }
  220.  
  221.   @InitCode:
  222. {$ENDIF}
  223.  
  224.         cli                           { disable ints during regs setup }
  225. {$IFDEF DebugVersion}
  226.         mov      ax, adwBootSeg
  227. {$ELSE}
  228.     sub     ax, ax
  229. {$ENDIF}
  230.         mov      ds, ax               { set seg registers to zero = ABS0 seg }
  231.         mov      es, ax
  232.         mov      ss, ax               { stack at $0000:$7C00 }
  233.         mov      sp, adwBootOfs
  234.  
  235.         sti                           { re-enable intrs }
  236.         cld                           { go forward }
  237.         mov      si, sp               { DS:SI -> 0:$7C00 }
  238.         mov      di, adwRelBootOfs    { ES:DI -> 0:$7E00 }
  239.         mov      cx, aSecSizeInWords  { words count }
  240.         rep      movsw                { relocate code to safe place }
  241.                       { jump to continue from new place }
  242.         db       aFarJumpOpCode       { Direct FAR Jump }
  243.     dw     adwRelBootOfs + (OFFSET @NewStart)
  244.     dw     adwBootSeg
  245.  
  246.                                       { messages for user }
  247.                       { offset to ref        =>  $1D }
  248.   @dbUserMenu_MSG:
  249.         db       "OS-MultBoot (C) 1992 D.Stefankov"
  250.         db       achCR,achLF
  251.                                       {** Hard-coded values, be carefully! **}
  252.                       { offset to ref        =>  $41 }
  253.                       { length of each entry =>  $16 }
  254.                       { offset of <None>     =>  $04 }
  255.         db       "[1] None OS           "
  256.     db     achCR, achLF
  257.  
  258.         db       "[2] None OS           "
  259.     db     achCR, achLF
  260.  
  261.         db       "[3] None OS           "
  262.     db     achCR, achLF
  263.  
  264.         db       "[4] None OS           "
  265.     db     achCR, achLF
  266.  
  267.         db       "Select:"
  268.         db       achNULL
  269.  
  270.   @LoadOS_MSG:
  271.         db       achCR,achLF
  272.         db       '.. Load OS ..'
  273.         db       achCR,achLF
  274.         db       achNULL
  275.  
  276.   @BadPartition_MSG:
  277.         db       achCR,achLF
  278.         db       '.. Bad Partition ..'
  279.         db       achNULL
  280.  
  281.   @ErrLoadOS_MSG:
  282.         db       achCR,achLF
  283.         db       '.. Error loading OS ..'
  284.         db       achNULL
  285.  
  286.   @BadOS_MSG:
  287.         db       achCR,achLF
  288.         db       '.. Missing OS ..'
  289.         db       achNULL
  290.  
  291.   @BadUserSelect_MSG:
  292.         db       achCR,achLF
  293.         db       '.. Invalid select ..'
  294.         db       achNULL
  295.  
  296.  
  297.   @AnyKey_MSG:
  298.         db       achCR,achLF
  299.         db       '.. Strike any key ..'
  300.         db       achNULL
  301.  
  302.  
  303.   @NewStart:
  304.         mov      ah, 0Fh              { get video mode }
  305.         int      aRomVideoDriver      { call ROM BIOS video driver }
  306.         mov      ah, 00h              { set video mode }
  307.         int      aRomVideoDriver      { call ROM BIOS video driver }
  308.  
  309.         mov      si, OFFSET  @dbUserMenu_MSG
  310.         call     @AsciizOutput        { Display string in format <ASCII+zero> }
  311.  
  312.         mov      ah, 00h              { get user char }
  313.         int      aRomKbdDriver        { call ROM BIOS keyboard driver }
  314.  
  315.         cmp      al, achOne           { test for match value }
  316.         jb       @BadEntry
  317.         cmp      al, achFour
  318.         ja       @BadEntry
  319.  
  320.         and      ax, $0007            { must in range 1..4 }
  321.         mov      cl, 4                { each entry in PT occupies }
  322.         shl      al, cl               { exactly 16 bytes }
  323.         mov      si, adwRelBootOfs + adwPartitionTable - aPartitonEntrySize
  324.         add      si, ax               { DS:SI -> Partition Table entry }
  325.  
  326.         mov      dx, [si]             { DH = head, DL = drive }
  327.         mov      cx, [si+2]           { CX = cyl/sec }
  328.         mov      ax, cx               { test valid info }
  329.         or       ax, dx
  330.         jz       @BadPartition        { jump if unable to load this }
  331.  
  332.         or       dl, 080h             { turn on a bit for fixed disk }
  333.         mov      bx, adwBootOfs       { ES:BX -> buffer }
  334.         mov      bp, 7                { retry count }
  335.  
  336.   @TryLoad:
  337.        mov      ax, 0201h             { read one sector from disk to memory }
  338.        int      aRomDiskDriver        { call ROM BIOS disk driver }
  339.        jnc      @LoadOk               { jump if driver says OK }
  340.        xor    ah, ah              { reset controller }
  341.        int    aRomDiskDriver          { call ROM BIOS disk driver }
  342.        dec      bp                    { decrement a retries counter }
  343.        jnz      @TryLoad
  344.                                       { may be disk bad? }
  345.        mov      si, OFFSET  @ErrLoadOS_MSG
  346.  
  347.   @UserWarning:
  348.         call     @AsciizOutput        { Display string in format <ASCII+zero> }
  349.  
  350.         mov      si, OFFSET  @AnyKey_MSG
  351.         call     @AsciizOutput        { Display string in format <ASCII+zero> }
  352.  
  353.         mov      ah, 00h              { get user char }
  354.         int      aRomKbdDriver        { call ROM BIOS keyboard driver }
  355.         jmp      @NewStart
  356.  
  357.   @LoadOk:                            { check boot ID }
  358.         cmp     word ptr [bx+adwBootMarkOfs], adwBootSecID
  359.         jne    @BadOS
  360.  
  361.         mov      si, OFFSET  @LoadOS_MSG
  362.         call     @AsciizOutput        { Display string in format <ASCII+zero> }
  363.         db     aFarJumpOpCode         { Direct Far Jump }
  364.         dw     adwBootOfs, adwBootSeg { address }
  365.  
  366.   @BadEntry:                          { invalid user option }
  367.         mov    si, OFFSET  @BadUserSelect_MSG
  368.         jmp    @UserWarning
  369.  
  370.   @BadOS:                             { non-bootable sector }
  371.         mov    si, OFFSET  @BadOS_MSG
  372.         jmp    @UserWarning
  373.  
  374.   @BadPartition:                      { bad partition table }
  375.         mov    si, OFFSET  @BadPartition_MSG
  376.         jmp    @UserWarning
  377.  
  378.  
  379.  {** _AsciizOutput  PROC NEAR **}
  380.   @AsciizOutput:                      
  381.         add    si, adwRelBootOfs      { fix problem with relocation }
  382.  
  383.   @NextChar:
  384.         lodsb                         { get char }
  385.         or       al, al               { AL is zero? }
  386.         jz       @Done                { exit if match }
  387.         push     si                   { preserve SI (may be destroyed for older BIOS versions!) }
  388.         mov      bx, 0007h            { white-on-black }
  389.         mov      ah, 0Eh              { TTY function }
  390.         int      aRomVideoDriver      { call ROM BIOS video driver }
  391.         pop      si                   { recover SI }
  392.         jmp      @NextChar
  393.  
  394.   @Done:
  395.         retn                          { return to caller }
  396.  {** _AsciizOutput  ENDP  **}
  397.  
  398. END; {end-asm}
  399. { _IPL_Code }
  400.  
  401.  
  402. PROCEDURE    _DummyProc;
  403. {* It is used for reference only. Don't remove this code!!! *}
  404. BEGIN
  405.   {** nothing!!! *}
  406. END;
  407. { _DummyProc }
  408.  
  409.  
  410.  
  411. {*=========================== FUNCTIONAL PART ==========================*}
  412.  
  413. FUNCTION  _fnsForceFileExtension(sFileName, sDefExt : STRING) : STRING;
  414. {* Add extension for filename if not present. *}
  415. BEGIN
  416.    IF (System.Pos(aDosExtMark,sFileName) = 0)
  417.      THEN sFileName := sFileName + aDosExtMark + sDefExt;
  418.    {if-then}
  419.   _fnsForceFileExtension := sFileName;
  420. END;
  421. { _fnsForceFileExtension }
  422.  
  423.  
  424. FUNCTION   _fnchGetFirstChar(sInput : STRING) : System.Char;
  425. {* Returns a first char from string. *}
  426. VAR
  427.   chTemp  :  System.Char;
  428.  
  429. BEGIN
  430.    IF (System.Length(sInput) <> 0)
  431.      THEN  chTemp := sInput[1]
  432.      ELSE  chTemp := System.Char(achNULL);
  433.    {if-then-else}
  434.   _fnchGetFirstChar := chTemp;
  435. END;
  436. { _fnchGetFirstChar }
  437.  
  438.  
  439.  
  440. {*=========================== PROCEDURAL PART ==========================*}
  441.  
  442. PROCEDURE    _CopyrightDisplay;
  443. {* Outputs the copyright notice. *}
  444. BEGIN
  445.      System.WriteLn(asPurpose+
  446.                     '  Version '+
  447.                     asVersion+
  448.                     ',  '+
  449.                     asCopyright+
  450.                     '  '+
  451.                     asAuthor);
  452. END;  { _CopyrightDisplay }
  453.  
  454.  
  455. {*============================== MAIN PART =============================*}
  456.  
  457. BEGIN
  458.  
  459.   {* copyright message *}
  460.     _CopyrightDisplay;
  461.  
  462.  
  463.   {* set a length of boot code, don't count TP RETF instruction *}
  464.      gdwOurBootRecLen := System.Ofs(_DummyProc) - System.Ofs(_IPL_Code) - 1;
  465.  
  466.  
  467.   {* test bootstrap procedure *}
  468. {$IFDEF  DebugVersion}
  469.     System.WriteLn(asProgramPrompt+'Debugging of boostrap procedure.');
  470.     asm
  471.       mov        ax,  aDebugOn        { no relocated code }
  472.     END;
  473.     {asm-end}
  474.  
  475.     _IPL_Code;
  476.  
  477.    System.Halt(errBootStrapDebug);
  478. {$ENDIF}
  479.  
  480.   {* test for match length of IPL *}
  481.      IF  (gdwOurBootRecLen > adwPartitionTable)
  482.        THEN  BEGIN
  483.          System.WriteLn(asProgramPrompt+'Bad size of loader code please re-code.');
  484.          System.Halt(errMismatchLoaderCode);
  485.              END;
  486.      {if-then}
  487.  
  488.   {* Read original master boot record *}
  489.     System.WriteLn(asProgramPrompt+'Reading of MBR.');
  490.     gbStatusOk := System.True;
  491.     asm
  492.         mov     dx, 0080h             { drive 0, head 0 }
  493.         mov     cx, 0001h             { cyl 0, sec 1 }
  494.         mov     ax, ds
  495.         mov     es, ax                { ES = Turbo DS }
  496.         mov     bx, OFFSET grecFixedDiskBoot
  497.         mov     ax, 0201h             { read 1 sector }
  498.         int     aRomDiskDriver        { ROM BIOS disk driver }
  499.         jnc     @Done
  500.                                       { at this point reading failed }
  501.         mov     gbStatusOk, System.False
  502.  
  503.      @Done:
  504.     END;
  505.     {ams-end}
  506.  
  507.   IF NOT(gbStatusOk)
  508.     THEN  BEGIN
  509.        System.WriteLn(asProgramPrompt+'Unable to read MBR from fixed disk.');
  510.        System.Halt(errBadReadFixedDisk);
  511.           END;
  512.   {if-then}
  513.  
  514.  
  515.   {* check for presence of installed loader *}
  516.      System.Move(grecFixedDiskBoot,gsTempInput[1],aMaxTpStrLen);
  517.      gsTempInput[0] := System.Char(aMaxTpStrLen);
  518.      IF  (System.Pos(asCopyrightNotice,gsTempInput) <> 0)
  519.        THEN  BEGIN
  520.           System.WriteLn(asProgramPrompt+asProgram+' loader found on fixed disk 0.');
  521.           System.Write(asProgramPrompt+'Copy description strings from installed copy (Y/N): ');
  522.           System.ReadLn(gsTempInput);
  523.  
  524.           IF  (System.UpCase(_fnchGetFirstChar(gsTempInput)) <> achNo)
  525.              THEN  BEGIN
  526.                 System.WriteLn(asProgramPrompt+'Copy description strings.');
  527.                 System.Move(System.Mem[System.Seg(grecFixedDiskBoot.dbReservedCode):
  528.                             (System.Ofs(grecFixedDiskBoot.dbReservedCode)+aOS_Desc_Start)],
  529.                             System.Mem[System.Seg(System.Addr(_IPL_Code)^):aOS_Desc_Start],
  530.                             aOS_Desc_Str_Len_Ext*aMaxAvailLogicalPartition);
  531.                    END;
  532.           {if-then}
  533.              END
  534.        ELSE
  535.           System.WriteLn(asProgramPrompt+asProgram+' loader not present.');
  536.      {if-then}
  537.  
  538.  
  539.   {* save original boot record *}
  540.      System.Write(asProgramPrompt+'Save original MBR (Y/N): ');
  541.      System.ReadLn(gsTempInput);
  542.      IF  ((System.UpCase(gsTempInput[1]) <> achNo) OR (gsTempInput = asBlank))
  543.        THEN  BEGIN
  544.          System.Write(asProgramPrompt+'Enter filename (def.ext.='+aDefExt+'): ');
  545.          System.ReadLn(gsTempInput);
  546.          IF (gsTempInput <> asBlank)
  547.            THEN  BEGIN
  548.               gsTempInput := _fnsForceFileExtension(gsTempInput,aDefExt);
  549.               System.WriteLn(asProgramPrompt+'Copy original MBR to file.');
  550.             {** no check for errors **}
  551.               System.Assign(gfOutStream,gsTempInput);
  552.               System.Rewrite(gfOutStream);
  553.               System.Write(gfOutStream,grecFixedDiskBoot);
  554.               System.Close(gfOutStream);
  555.                  END;
  556.          {if-then}
  557.              END;
  558.      {if-then}
  559.  
  560.  
  561.   {* make a new boot record *}
  562.     System.WriteLn(asProgramPrompt+'Copy loader code.');
  563.     System.Move(System.Mem[System.Seg(System.Addr(_IPL_Code)^):0],
  564.                            grecFixedDiskBoot,
  565.                            gdwOurBootRecLen);
  566.  
  567.   {* Ask user about installation. *}
  568.      System.Write(asProgramPrompt+'Install OS-MBoot. Are you sure (N/Y): ');
  569.      System.ReadLn(gsTempInput);
  570.      IF  (System.UpCase(_fnchGetFirstChar(gsTempInput)) <> achYes)
  571.        THEN  BEGIN
  572.          System.WriteLn(asProgramPrompt+'Aborted by user.');
  573.          System.Halt(errUserInstallAbort);
  574.              END;
  575.      {if-then}
  576.  
  577.  
  578.   {* Ask user about OS select. *}
  579.      gbStatusOk := System.False;
  580.  
  581.      REPEAT
  582.       {* display current settings *}
  583.        System.WriteLn(asProgramPrompt+'Operating System (OS)  Define Menu: ');
  584.        FOR  gdbIndex  := 0  TO  aMaxAvailLogicalPartition-1  DO
  585.        BEGIN
  586.          System.Move(grecFixedDiskBoot.dbReservedCode[aOS_Desc_Start+(aOS_Desc_Str_Len_Ext*gdbIndex)],
  587.                      gsTempInput[1],
  588.                      aOS_Desc_Str_Len);
  589.          gsTempInput[0] := System.Char(aOS_Desc_Str_Len);
  590.          {* Check for free slot *}
  591.          IF  (grecFixedDiskBoot.recDiskPartitionsTable[gdbIndex].dwStartingCylSec = 0)
  592.            THEN  gsTempInput := gsTempInput + asFreeSlot
  593.            ELSE  gsTempInput := gsTempInput + asNonFreeSlot;
  594.          {if-then-else}
  595.          System.WriteLn(gsTempInput);
  596.        END;
  597.        {for-to-do}
  598.        System.WriteLn('[Q] Quit');
  599.        System.Write('Select your option(1,2,3,4,Q): ');
  600.  
  601.      {* get user input *}
  602.        System.ReadLn(gsTempInput);
  603.        gchIn := System.UpCase(_fnchGetFirstChar(gsTempInput));
  604.  
  605.        IF (gsTempInput <> asBlank)
  606.          THEN  CASE  gchIn  OF
  607.                         achOne..achFour  :  BEGIN
  608.        {* only 4 logical partitions enabled *}
  609.          gdbIndex := System.Byte(gchIn) - System.Byte(achOne);
  610.          System.Write(asProgramPrompt+'Enter OS/ID string (up ',(aOS_Desc_Str_Len-aOS_Desc_Ofs),' chars): ');
  611.          System.ReadLn(gsTempInput);
  612.  
  613.          IF  (gsTempInput <> asBlank)
  614.            THEN  BEGIN
  615.        {* cut string if need *}
  616.          WHILE  (System.Length(gsTempInput) > (aOS_Desc_Str_Len-aOS_Desc_Ofs)) DO
  617.            System.Delete(gsTempInput,System.Length(gsTempInput),1);
  618.          {while-do}
  619.        {* copy ID string *}
  620.          System.Move(gsTempInput[1],
  621.                      grecFixedDiskBoot.dbReservedCode[aOS_Desc_Start+((aOS_Desc_Str_Len+2)*gdbIndex)+aOS_Desc_Ofs],
  622.                      System.Length(gsTempInput));
  623.                  END
  624.          {if-then}
  625.                                      END;
  626.                         aQuit       :  gbStatusOk := System.True;
  627.                  ELSE
  628.                      System.WriteLn(asProgramPrompt+'Bad selection.');
  629.                END;
  630.                {case-of}
  631.        {if-then}
  632.      UNTIL (gbStatusOk);
  633.      {repeat-until}
  634.  
  635.  
  636.   {* Ask user about writing. *}
  637.      System.Write(asProgramPrompt+'Write a new IPL. Are you sure (N/Y): ');
  638.      System.ReadLn(gsTempInput);
  639.      IF  (System.UpCase(_fnchGetFirstChar(gsTempInput)) <> achYes)
  640.        THEN  BEGIN
  641.          System.WriteLn(asProgramPrompt+'Aborted by user.');
  642.          System.Halt(errUserWriteAbort);
  643.              END;
  644.      {if-then}
  645.  
  646.  
  647.   {* Write a new master boot record *}
  648.     System.WriteLn(asProgramPrompt+'Writing of MBR.');
  649.     gbStatusOk := System.True;
  650.     asm
  651.         mov     dx, 0080h             { drive 0, head 0 }
  652.         mov     cx, 0001h             { cyl 0, sec 1 }
  653.         mov     ax, ds
  654.         mov     es, ax                { ES = Turbo DS }
  655.         mov     bx, OFFSET grecFixedDiskBoot
  656.         mov     ax, 0301h             { write 1 sector }
  657.         int     aRomDiskDriver        { ROM BIOS disk driver }
  658.         jnc     @Done
  659.                                       { we know that writing failed here }
  660.         mov     gbStatusOk, System.False
  661.  
  662.      @Done:
  663.     END;
  664.     {asm-end}
  665.  
  666.   IF NOT(gbStatusOk)
  667.     THEN  BEGIN
  668.        System.WriteLn(asProgramPrompt+'Unable to write MBR to fixed disk.');
  669.        System.Halt(errBadWriteFixedDisk);
  670.           END;
  671.   {if-then}
  672.  
  673.  
  674.   {* final report *}
  675.     System.WriteLn(asProgramPrompt+'Done.');
  676.  
  677.   {* System.Halt(errTerminateOk); *}
  678. END.
  679.